package sample;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;

import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
public class Controller implements Initializable, MqttCallback {
    public TableView<CarPark> table_carPark;
    public TableView<Record> table_record;
    public LineChart<String, Number> chart_carPark;
    public Label label_status_left;
    public Label label_status_right;

    private ObservableList<CarPark> carParkObservableList = FXCollections.observableArrayList();
    private ObservableList<Record> recordObservableList = FXCollections.observableArrayList();
    private String server = "mqtt.dongluhitec.net";
    private String port = "1883";
    private String username = "dongyunsmart";
    private String password = "smart@512809";
    private ScheduledExecutorService scheduledExecutorService;
    private Integer lastRecordSize = 0;

    public void initialize(URL location, ResourceBundle resources) {
        table_carPark.setItems(carParkObservableList);
        table_record.setItems(recordObservableList);

        scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
        scheduledExecutorService.scheduleWithFixedDelay(drawChartRunnable, 10, 5, TimeUnit.SECONDS);
        scheduledExecutorService.schedule(() -> { Platform.runLater(() -> monitor_start(new ActionEvent())); }, 1, TimeUnit.SECONDS);

        table_carPark.setRowFactory( tv -> {
            TableRow<CarPark> row = new TableRow<>();
            row.setOnMouseClicked(event -> {
                if (event.getClickCount() == 2 && (! row.isEmpty()) ) {
                    CarPark rowData = row.getItem();

                    TextInputDialog textInputDialog = new TextInputDialog(rowData.getCarParkName());
                    Optional<String> showAndWait = textInputDialog.showAndWait();
                    showAndWait.ifPresent(rowData::setCarParkName);

                    log.debug("设置停车场名称:{}",rowData.getCarParkName());
                }
            });
            return row ;
        });

        scheduledExecutorService.scheduleWithFixedDelay(()->{
            Platform.runLater(()->{
                String toString = LocalDateTime.now().minusHours(1).toString();
                List<Record> collect = recordObservableList.stream().filter(f -> f.getCarTime().compareTo(toString) > 0).collect(Collectors.toList());
                recordObservableList.setAll(collect);
            });
        },10,60,TimeUnit.SECONDS);

        scheduledExecutorService.scheduleAtFixedRate(()->{

            try {
                boolean connected = Mqtts.getInstance().getMqttClient().isConnected();
                if(connected){
                    log.debug("连接mqtt服务器状态正常");
                    return;
                }
                log.debug("正在重连mqtt服务器");
                Mqtts.getInstance().getMqttClient().reconnect();
            } catch (MqttException e) {
                log.error("mqtt服务重连异常",e);
            }
        },10,10,TimeUnit.SECONDS);
    }

    private Runnable drawChartRunnable = new Runnable() {
        @Override
        public void run() {
            log.debug("开始绘制图表");
            if (recordObservableList.size() == lastRecordSize) {
                log.debug("绘制图表无变化");
                return;
            }
            lastRecordSize = recordObservableList.size();
            ArrayList<Record> records = new ArrayList<>(recordObservableList);
            Map<String, List<Record>> collect = records.stream().collect(Collectors.groupingBy(Record::getCarParkTopic));
            final List<XYChart.Series<String, Number>> list = new ArrayList<>();
            for (Map.Entry<String, List<Record>> stringListEntry : collect.entrySet()) {
                Map<String, List<Record>> listMap = stringListEntry.getValue().stream().collect(Collectors.groupingBy(g -> g.getCarTime().substring(0, 16)));
                XYChart.Series<String, Number> stringNumberSeries = new XYChart.Series<>();
                for (CarPark carPark : carParkObservableList) {
                    if (carPark.getCarParkTopic().equals(stringListEntry.getKey())) {
                        stringNumberSeries.setName(carPark.getCarParkName());
                    }
                }
                ArrayList<String> keys = new ArrayList<>(listMap.keySet());
                keys.sort((o1, o2) -> o1.compareTo(o2));
                for (String key : keys) {
                    log.debug("carpark:{} Series key:{}",stringListEntry.getKey(), key);
                    stringNumberSeries.getData().add(new XYChart.Data<>(key, listMap.get(key).size()));
                }
                stringNumberSeries.getData().sorted((o1, o2) -> o1.getXValue().compareTo(o2.getXValue()));
                list.add(stringNumberSeries);
            }
            Platform.runLater(() -> chart_carPark.getData().setAll(list));
            log.debug("绘制图表完成");
        }
    };

    public void exit(ActionEvent actionEvent) {
        Optional<ButtonType> showConfirm = Alerts.create().title("提示").headerText("确定要退出吗").showConfirmation();
        showConfirm.ifPresent(p -> System.exit(1));
    }

    public void config_mqtt(ActionEvent actionEvent) {
        try {
            TextField server = new TextField(this.server);
            Label mqtt_server = new Label("mqtt server");
            mqtt_server.setPrefWidth(100);
            HBox hBox0 = new HBox(10, mqtt_server, server);
            TextField port = new TextField(this.port);
            Label mqtt_port = new Label("mqtt port");
            mqtt_port.setPrefWidth(100);
            HBox hBox1 = new HBox(10, mqtt_port, port);
            TextField username = new TextField(this.username);
            Label mqtt_username = new Label("mqtt username");
            mqtt_username.setPrefWidth(100);
            HBox hBox2 = new HBox(10, mqtt_username, username);
            TextField password = new TextField(this.password);
            Label mqtt_password = new Label("mqtt password");
            mqtt_password.setPrefWidth(100);
            HBox hBox3 = new HBox(10, mqtt_password, password);
            VBox vBox = new VBox(10, hBox0, hBox1, hBox2, hBox3);
            vBox.setPadding(new Insets(10));

            Optional<ButtonType> showConfirm = Alerts.create().title("设置mqtt服务器").dialogPane(vBox).showConfirmation();
            if (showConfirm.isPresent()) {
                this.server = server.getText().trim();
                this.port = port.getText().trim();
                this.username = username.getText().trim();
                this.password = password.getText().trim();
                Alerts.create().title("提示").headerText("设置成功").showConfirmation();
            }
        } catch (Exception e) {
            Alerts.create().showException(e);
        }
    }

    public void monitor_start(ActionEvent actionEvent) {
        try {
            MqttClient mqttClient = Mqtts.getInstance().getMqttClient();
            if (mqttClient != null) {
                Alerts.create().title("提示").headerText("mqtt 监控己启动，请先停止再使用该操作").showWarning();
                return;
            }

            boolean connect = Mqtts.getInstance().connect(this.server, this.port, this.username, this.password);
            if (connect) {
                Mqtts.getInstance().getMqttClient().subscribe("lightcar/ipms/+");
                Mqtts.getInstance().getMqttClient().setCallback(this);
                Alerts.create().title("提示").headerText("启动成功").showInformation();
            } else {
                Alerts.create().title("提示").headerText("启动失败").showError();
            }
        } catch (Exception e) {
            e.printStackTrace();
            Alerts.create().showException(e);
        }
    }

    public void monitor_end(ActionEvent actionEvent) {
        MqttClient mqttClient = Mqtts.getInstance().getMqttClient();
        if (mqttClient == null) {
            Alerts.create().title("提示").headerText("mqtt 监控己停止，请先启动再使用该操作").showWarning();
        }
    }

    public void connectionLost(Throwable throwable) {
        log.error("mqtt服务异常",throwable);
    }

    public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
        String[] split = topic.split("/");
        CarPark carPark = new CarPark();
        carPark.setCarParkName(split[split.length - 1]);
        carPark.setCarParkTopic(topic);

        Platform.runLater(() -> {
            boolean contains = carParkObservableList.contains(carPark);
            if (!contains) {
                carParkObservableList.add(carPark);
            }
            String message = new String(mqttMessage.getPayload(), StandardCharsets.UTF_8);
            log.info("topic:\t{}", topic);
            log.info("message:\t{}", message);
            JSONObject jsonObject = JSON.parseObject(message).getJSONObject("data");
            String carNum = jsonObject.getString("carNum");
            Long fee = jsonObject.getLong("fee");

            if (carNum == null || fee == null) {
                return;
            }

            Record record = new Record();
            record.setCarParkTopic(topic);
            record.setCarCode(carNum);
            record.setCarFeeMoney(String.valueOf(fee / 100));
            record.setCarTime(LocalDateTime.now().toString());

            record.setCarDetail(message);
            recordObservableList.sort((o1, o2) -> o2.getCarTime().compareTo(o1.getCarTime()));
            recordObservableList.add(record);
        });
    }

    public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {

    }
}
